home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / rhythmbox / plugins / rb / Loader.py < prev    next >
Encoding:
Python Source  |  2009-04-07  |  8.9 KB  |  331 lines

  1. # -*- Mode: python; coding: utf-8; tab-width: 8; indent-tabs-mode: t; -*- 
  2. #
  3. # Copyright (C) 2009 - Jonathan Matthew
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2, or (at your option)
  8. # any later version.
  9. #
  10. # The Rhythmbox authors hereby grant permission for non-GPL compatible
  11. # GStreamer plugins to be used and distributed together with GStreamer
  12. # and Rhythmbox. This permission is above and beyond the permissions granted
  13. # by the GPL license by which Rhythmbox is covered. If you modify this code
  14. # you may extend this exception to your version of the code, but you are not
  15. # obligated to do so. If you do not wish to do so, delete this exception
  16. # statement from your version.
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. # GNU General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU General Public License
  23. # along with this program; if not, write to the Free Software
  24. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
  25.  
  26. import gobject
  27. import gtk
  28.  
  29. def callback_with_gdk_lock(callback, data, args):
  30.     gtk.gdk.threads_enter()
  31.     v = callback(data, *args)
  32.     gtk.gdk.threads_leave()
  33.     return v
  34.  
  35.  
  36. class GioLoader(object):
  37.     def __init__ (self):
  38.         self._cancel = gio.Cancellable()
  39.  
  40.     def _contents_cb (self, file, result):
  41.         try:
  42.             (contents, length, etag) = file.load_contents_finish(result)
  43.             callback_with_gdk_lock(self.callback, contents, self.args)
  44.         except gio.Error, e:
  45.             # somehow check if we just got cancelled
  46.             callback_with_gdk_lock(self.callback, None, self.args)
  47.  
  48.     def get_url (self, url, callback, *args):
  49.         self.url = url
  50.         self.callback = callback
  51.         self.args = args
  52.         try:
  53.             file = gio.File(url)
  54.             file.load_contents_async(callback = self._contents_cb, cancellable=self._cancel)
  55.         except Exception, e:
  56.             print "error getting contents of %s: %s" % e
  57.             callback(None, *args)
  58.  
  59.     def cancel (self):
  60.         self._cancel.cancel()
  61.  
  62.  
  63. class GioChunkLoader(object):
  64.     def __init__ (self):
  65.         self._cancel = gio.Cancellable()
  66.  
  67.     def _callback(self, result):
  68.         return self.callback(result, self.total, *self.args)
  69.  
  70.     def _callback_gdk(self, result):
  71.         gtk.gdk.threads_enter()
  72.         v = self._callback(result)
  73.         gtk.gdk.threads_leave()
  74.         return v
  75.  
  76.     def _read_cb(self, stream, result):
  77.         try:
  78.             data = stream.read_finish(result)
  79.         except gio.Error, e:
  80.             print "error reading file %s: %s" % (self.uri, e.message)
  81.             stream.close()
  82.             self._callback_gdk(e)
  83.  
  84.         if (self._callback_gdk(data) is not False) and data:
  85.             def again():
  86.                 stream.read_async (self.chunksize, self._read_cb, cancellable=self._cancel)
  87.                 return False
  88.             gobject.idle_add(again)
  89.         else:
  90.             # finished or cancelled by callback
  91.             stream.close()
  92.  
  93.     def _open_cb(self, file, result):
  94.         try:
  95.             stream = file.read_finish(result)
  96.         except gio.Error, e:
  97.             print "error reading file %s: %s" % (self.uri, e.message)
  98.             self._callback_gdk(e)
  99.         
  100.         stream.read_async(self.chunksize, self._read_cb, cancellable=self._cancel)
  101.  
  102.     def _info_cb(self, file, result):
  103.         try:
  104.             info = file.query_info_finish(result)
  105.             self.total = info.get_attribute_uint64(gio.FILE_ATTRIBUTE_STANDARD_SIZE)
  106.  
  107.             file.read_async(self._open_cb, cancellable=self._cancel)
  108.         except gio.Error, e:
  109.             print "error checking size of source file %s: %s" % (self.uri, e.message)
  110.             self._callback_gdk(e)
  111.  
  112.  
  113.     def get_url_chunks (self, uri, chunksize, want_size, callback, *args):
  114.         try:
  115.             self.uri = uri
  116.             self.chunksize = chunksize
  117.             self.total = 0
  118.             self.callback = callback
  119.             self.args = args
  120.  
  121.             file = gio.File(uri)
  122.             if want_size:
  123.                 file.query_info_async(self._info_cb, gio.FILE_ATTRIBUTE_STANDARD_SIZE, cancellable=self._cancel)
  124.             else:
  125.                 file.read_async(self._open_cb, cancellable=self.cancel)
  126.         except gio.Error, e:
  127.             print "error reading file %s: %s" % (uri, e.message)
  128.             self._callback(e)
  129.  
  130.     def cancel (self):
  131.         self._cancel.cancel()
  132.  
  133.  
  134. class GioUpdateCheck(object):
  135.     def __init__ (self):
  136.         self._cancel = gio.Cancellable()
  137.  
  138.     def _file_info_cb (self, file, result):
  139.         try:
  140.             rfi = file.query_info_finish(result)
  141.  
  142.             remote_mod = rfi.get_attribute_uint64(gio.FILE_ATTRIBUTE_TIME_MODIFIED)
  143.             callback_with_gdk_lock(self.callback, remote_mod != self.local_mod, self.args)
  144.         except Exception, e:
  145.             print "error checking for update: %s" % e
  146.             callback_with_gdk_lock(self.callback, False, self.args)
  147.  
  148.     def check_for_update (self, local, remote, callback, *args):
  149.         self.local = local
  150.         self.remote = remote
  151.         self.callback = callback
  152.         self.args = args
  153.  
  154.         try:
  155.             lf = gio.File(local)
  156.             lfi = lf.query_info(gio.FILE_ATTRIBUTE_TIME_MODIFIED)
  157.             self.local_mod = lfi.get_attribute_uint64(gio.FILE_ATTRIBUTE_TIME_MODIFIED)
  158.  
  159.             rf = gio.File(remote)
  160.             rf.query_info_async(self._file_info_cb, gio.FILE_ATTRIBUTE_TIME_MODIFIED, cancellable=self._cancel)
  161.         except Exception, e:
  162.             print "error checking for update: %s" % e
  163.             self.callback(True, *self.args)
  164.  
  165.     def cancel (self):
  166.         self._cancel.cancel()
  167.  
  168.  
  169. class GnomeVFSLoader (object):
  170.     def __init__ (self):
  171.         self.chunk = 4096
  172.  
  173.     def _read_cb (self, handle, buffer, exc_type, bytes_req):
  174.         if exc_type:
  175.             if issubclass (exc_type, gnomevfs.EOFError):
  176.                 callback_with_gdk_lock (self.callback, self.data, self.args)
  177.                 handle.close (lambda *args: None)
  178.             else:
  179.                 callback_with_gdk_lock (self.callback, None, self.args)
  180.                 handle.close (lambda *args: None)
  181.             return
  182.              
  183.         self.data += buffer
  184.         handle.read (self.chunk, self._read_cb)
  185.  
  186.     def _open_cb (self, handle, exc_type):
  187.         if exc_type:
  188.             callback_with_gdk_lock (self.callback, None, self.args)
  189.             return
  190.  
  191.         self.handle = handle
  192.         self.data = ""
  193.         handle.read (self.chunk, self._read_cb)
  194.     
  195.     def get_url (self, url, callback, *args):
  196.         self.url = url
  197.         self.callback = callback
  198.         self.args = args
  199.         gnomevfs.async.open (url, self._open_cb)
  200.  
  201.     def cancel (self):
  202.         self.handle.cancel()
  203.  
  204.  
  205. class GnomeVFSChunkLoader (object):
  206.     def __init__ (self):
  207.         pass
  208.  
  209.     def _callback(self, result):
  210.         return self.callback(result, self.total, *self.args)
  211.  
  212.     def _callback_gdk(self, result):
  213.         gtk.gdk.threads_enter()
  214.         v = self._callback(result)
  215.         gtk.gdk.threads_leave()
  216.         return v
  217.  
  218.     def _read_cb (self, handle, buffer, exc_type, bytes_requested):
  219.         if exc_type:
  220.             if issubclass (exc_type, gnomevfs.EOFError):
  221.                 self._callback_gdk (None)
  222.             else:
  223.                 self._callback_gdk (exc_type())
  224.             handle.close (lambda *args: None)
  225.         else:
  226.             if self._callback_gdk (buffer) is False:
  227.                 handle.close(lambda *args: None)
  228.             else:
  229.                 handle.read (self.chunksize, self._read_cb)
  230.  
  231.  
  232.     def _open_cb (self, handle, exc_type):
  233.         if exc_type:
  234.             self._callback_gdk (exc_type())
  235.         else:
  236.             handle.read (self.chunksize, self._read_cb)
  237.  
  238.     def _info_cb (self, handle, results):
  239.         try:
  240.             (uri, exc, info) = results[0]
  241.             self.total = info.size
  242.         except ValueError:
  243.             pass
  244.  
  245.         self.handle = gnomevfs.async.open (self.vfs_uri, self._open_cb)
  246.  
  247.     def get_url_chunks (self, uri, chunksize, want_size, callback, *args):
  248.         self.uri = uri
  249.         self.chunksize = chunksize
  250.         self.total = 0
  251.         self.callback = callback
  252.         self.args = args
  253.         self.vfs_uri = gnomevfs.URI(uri)
  254.         if want_size:
  255.             self.handle = gnomevfs.async.get_file_info ((self.vfs_uri,), self._info_cb)
  256.         else:
  257.             self.handle = gnomevfs.async.open (self.vfs_uri, self._open_cb)
  258.  
  259.     def cancel (self):
  260.         if self.handle:
  261.             self.handle.cancel()
  262.  
  263.  
  264. class GnomeVFSUpdateCheck (object):
  265.     def __init__ (self):
  266.         pass
  267.  
  268.     def _info_cb (self, handle, results):
  269.         (local_uri, local_exc, local_info) = results[0]
  270.         (remote_uri, remote_exc, remote_info) = results[1]
  271.  
  272.         result = True
  273.  
  274.         if remote_exc:
  275.             print "error checking remote URI %s: %s" % (self.remote, remote_exc)
  276.             result = False
  277.         elif local_exc:
  278.             if issubclass (local_exc, gnomevfs.NotFoundError):
  279.                 print "local URI %s not found" % self.local
  280.             else:
  281.                 print "error checking local URI %s: %s" % (self.local, local_exc)
  282.         else:
  283.             try:
  284.                 result = (remote_info.mtime > local_info.mtime)
  285.             except ValueError, e:
  286.                 print "error comparing modification times: %s" % e
  287.         
  288.         callback_with_gdk_lock (self.callback, result, self.args)
  289.  
  290.  
  291.     def check_for_update (self, local, remote, callback, *args):
  292.         self.callback = callback
  293.         self.args = args
  294.         self.local = local
  295.         self.remote = remote
  296.  
  297.         uris = (gnomevfs.URI(local), gnomevfs.URI(remote))
  298.         self.handle = gnomevfs.async.get_file_info (uris, self._info_cb)
  299.  
  300.     def cancel (self):
  301.         self.handle.cancel ()
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308. # now figure out which set of implementations to use
  309.  
  310. use_gio = False
  311. try:
  312.     import gio
  313.     # before 2.16.0, file.load_contents_async didn't work correctly
  314.     if gio.pygio_version > (2,15,4):
  315.         use_gio = True
  316. except:
  317.     # probably don't have gio at all
  318.     pass
  319.  
  320. if use_gio:
  321.     Loader = GioLoader
  322.     ChunkLoader = GioChunkLoader
  323.     UpdateCheck = GioUpdateCheck
  324. else:
  325.     import gnomevfs
  326.     Loader = GnomeVFSLoader
  327.     ChunkLoader = GnomeVFSChunkLoader
  328.     UpdateCheck = GnomeVFSUpdateCheck
  329.  
  330.